// ==============================================================================
//
// software development kit v 3.0
// shared math unit
//
// copyright (c) 2008-2009 gear pair games
//
// copyright and license exceptions noted in source
//
// ==============================================================================

unit math;

// discrition:
// glsl-delphi
// float -
// int   -
// bool - true-false
// vec2, vec3, vec4 - float-vector (flaot 2, 3, 4.);
// ivec2, ivec3, ivec4 - int-vector;
// bvec2, bvec3, bvec4 - bool-vctor;
// mat2, mat3, mat4 - float-matrix (flaot 2x2, 3x3, 4x4.);

interface

// include other pas-file

uses
  types,
  enums;

// const std value
const
  const_epsilon = 0.0001;

  // float:

type
  enumvecdata = ( vxy, vxyz, vxyzw, vcell, vdata, vcolor, vcol, vmat2, vscrpos, veuler, vtexcoord );

{ std::face }
  face = packed record
    case enumvecdata of
     vxyz :
     ( x, y, z : ushort );
     vcell :
     ( one, two, three : ushort );
  end;

// void
  pface = ^face;
  faceArr = array [ ushort ] of face;
  pfaceArr = ^faceArr;

{ std::vec2 }
  vec2 = packed record
    case enumvecdata of
      // float
     vxy :
     ( x, y : float );
     vdata :
     ( xy : array [ 0 .. 1 ] of float );
  end;

{ std::vec2i }
  vec2i = packed record
    case enumvecdata of
      // float
     vxy :
     ( x, y : int );
     vcell :
     ( width, height : int );
     vdata :
     ( xy : array [ 0 .. 1 ] of int );
  end;

{ std::vec3 }
  vec3 = packed record
    class operator explicit( const value : float ) : vec3;
    inline;
    // operators + - * / ==
    class operator add( const v1, v2 : vec3 ) : vec3;
    inline;
    class operator subtract( const v1, v2 : vec3 ) : vec3;
    inline;
    class operator divide( const v1, v2 : vec3 ) : vec3;
    inline;
    class operator multiply( const v1, v2 : vec3 ) : vec3;
    inline;
    class operator multiply( const v : vec3; const f : float ) : vec3;
    inline;
    class operator equal( const v1, v2 : vec3 ) : bool;
    inline;

    case enumvecdata of
// single
     vxyz :
     ( x, y, z : float );
// xyz
     vdata :
     ( xyz : array [ 0 .. 2 ] of float );
// color
     vcolor :
     ( r, g, b : float );
// xy
     vxy :
     ( xy : vec2 );
// euler
     veuler :
     ( pitch, yow, roll : float );
// texcoord
     vtexcoord :
     ( t, s, sign : float );
  end;

// void
  pvec3 = ^vec3;
  vec3arr = array [ ushort ] of vec3;
  pvec3arr = ^vec3arr;

{ std::vec3i }
  vec3i = packed record
{ ff- }
    class operator explicit( const value : int ) : vec3i;
    inline;
    // operators + - * / ==
    class operator add( const v1, v2 : vec3i ) : vec3i;
    inline;
    class operator subtract( const v1, v2 : vec3i ) : vec3i;
    inline;
    class operator divide( const v1, v2 : vec3i ) : vec3i;
    inline;
    class operator multiply( const v1, v2 : vec3i ) : vec3i;
    inline;
    class operator multiply( const v : vec3i; const f : int ) : vec3i;
    inline;
    class operator equal( const v1, v2 : vec3i ) : bool;
    inline;
{ ff+ }
    case enumvecdata of
  // single
     vxyz :
     ( x, y, z : int );
  // xyz
     vdata :
     ( xyz : array [ 0 .. 2 ] of int );
  // color
     vcolor :
     ( r, g, b : int );
  // xy
     vxy :
     ( xy : vec2i );
  end;

{ std::vec4 }

  vec4 = packed record
{ ff- }
    class operator explicit( const value : float ) : vec4;
    inline;
    // operators + - * / ==
    class operator add( const v1, v2 : vec4 ) : vec4;
    inline;
    class operator subtract( const v1, v2 : vec4 ) : vec4;
    inline;
    class operator divide( const v1, v2 : vec4 ) : vec4;
    inline;
    class operator multiply( const v1, v2 : vec4 ) : vec4;
    inline;
    class operator multiply( const v : vec4; const f : float ) : vec4;
    inline;
    class operator equal( const v1, v2 : vec4 ) : bool;
    inline;
{ ff+ }
    case enumvecdata of
    // single
     vxyzw :
     ( x, y, z, w : float );
    // xyzw
     vdata :
     ( xyzw : array [ 0 .. 3 ] of float );
    // color
     vcolor :
     ( r, g, b, a : float );
    // vec2
     vxy :
     ( xy : vec2 );
    // vec3
     vxyz :
     ( xyz : vec3 );
  end;

// void
  pvec4 = ^vec4;

{ std::quat }
  quat = vec4;

{ std::vec4i }

  vec4i = packed record
{ ff- }
    class operator explicit( const value : int ) : vec4i;
    inline;
    // operators + - * / ==
    class operator add( const v1, v2 : vec4i ) : vec4i;
    inline;
    class operator subtract( const v1, v2 : vec4i ) : vec4i;
    inline;
    class operator divide( const v1, v2 : vec4i ) : vec4i;
    inline;
    class operator multiply( const v1, v2 : vec4i ) : vec4i;
    inline;
    class operator multiply( const v : vec4i; const f : int ) : vec4i;
    inline;
    class operator equal( const v1, v2 : vec4i ) : bool;
    inline;
{ ff+ }
    case enumvecdata of
    // single
     vxyzw :
     ( x, y, z, w : int );
    // xyzw
     vdata :
     ( xyzw : array [ 0 .. 3 ] of int );
    // color
     vcolor :
     ( r, g, b, a : int );
    // vec2
     vxy :
     ( xy : vec2i );
    // vec3
     vxyz :
     ( xyz : vec3i );
     vscrpos :
     ( pos, size : vec2i );
  end;

{ std::mat2 }

  mat2 = packed record
    case enumvecdata of
    // single
     vcol :
     ( col00, col01, col02, col03,
      // first  colum
     col10, col11, col12, col13 // second colum
     : float );
     vxyzw :
     ( col : array [ 0 .. 1 ] of vec4 );
  end;

{ std::mat4 }

  mat4 = packed record // mult
    { ff- }
    class operator multiply( const m1, m2 : mat4 ) : mat4;
    inline;
    class operator multiply( const m1 : mat4; const v2 : vec4 ) : vec4;
    inline;
    { ff }
    case enumvecdata of
// single
     vcol :
     ( col00, col01, col02, col03,
// first  colum
     col10, col11, col12, col13,
// second colum
     col20, col21, col22, col23,
// third  colum
     col30, col31, col32, col33 // fourth colum
     : float );
     vxyzw :
     ( col : array [ 0 .. 3 ] of vec4 );
     vmat2 :
     ( mat2 : array [ 0 .. 1 ] of mat2 );
     vcell :
     ( cell : array [ 0 .. 15 ] of float );
     vdata :
     ( rows : array [ 0 .. 3, 0 .. 3 ] of float );
     vscrpos :
     ( first, second, third, pos : vec4 );
  end;

  pmat4 = ^mat4;

{ std::aabbox }

  aabbox = packed record
    case enumvecdata of
     vxyz :
     ( min, max : vec3 );
     vdata :
     ( minmax : array [ 0 .. 5 ] of float );
  end;

function max( const x, y : float ) : float; overload; inline;
function min( const x, y : float ) : float; overload; inline;
function max( const x, y : int ) : int; overload; inline;
function min( const x, y : int ) : int; overload; inline;

function clamp( const value, minf, maxf : float ) : float; overload; inline;
function clamp( const value, minf, maxf : int ) : int; overload; inline;
function clamp( const value, minf, maxf : time ) : time; overload; inline;

// vec2
function _vec2( const x, y : float ) : vec2; overload; inline;
function _vec2( const value : float ) : vec2; overload; inline;

// vec3
function _vec3( const value : float ) : vec3; overload; inline;
function _vec3( const xy : vec2; const z : float ) : vec3; overload; inline;
function _vec3( const fx, fy, fz : float ) : vec3; overload; inline;
function add( const v1, v2 : vec3 ) : vec3; overload; inline;
function sub( const v1, v2 : vec3 ) : vec3; overload; inline;
function divide( const v1, v2 : vec3 ) : vec3; overload; inline;
function cross( const v1, v2 : vec3 ) : vec3; overload; inline;
function mul( const v1, v2 : vec3 ) : vec3; overload; inline;
function mul( const v : vec3; const f : float ) : vec3; overload; inline;
function dot( const v1, v2 : vec3 ) : float; overload; inline;
function normalize( const v : vec3 ) : vec3; overload; inline;
function lengthsqr( const v : vec3 ) : float; overload; inline;
function length( const v : vec3 ) : float; overload; inline;
function cmp( const v1, v2 : vec3 ) : bool; overload; inline;

// vec3i
function _vec3i( const value : int ) : vec3i; overload; inline;
function _vec3i( const xy : vec2i; const z : int ) : vec3i; overload; inline;
function _vec3i( const fx, fy, fz : int ) : vec3i; overload; inline;
function add( const v1, v2 : vec3i ) : vec3i; overload; inline;
function sub( const v1, v2 : vec3i ) : vec3i; overload; inline;
function divide( const v1, v2 : vec3i ) : vec3i; overload; inline;
function mul( const v1, v2 : vec3i ) : vec3i; overload; inline;
function mul( const v : vec3i; const f : int ) : vec3i; overload; inline;
function cross( const v1, v2 : vec3i ) : vec3i; overload; inline;
function dot( const v1, v2 : vec3i ) : int; overload; inline;
function cmp( const v1, v2 : vec3i ) : bool; overload; inline;

// vec4
function _vec4( const value : float ) : vec4; overload; inline;
function _vec4( const val3 : vec3; const w : float ) : vec4; overload; inline;
function _vec4( const fx, fy, fz, fw : float ) : vec4; overload; inline;
function cmp( const v1, v2 : vec4 ) : bool; overload; inline;

// vec4i
function _vec4i( const value : int ) : vec4i; overload; inline;
function _vec4i( const val3i : vec3i; const w : int ) : vec4i; overload; inline;
function _vec4i( const fx, fy, fz, fw : int ) : vec4i; overload; inline;
function cmp( const v1, v2 : vec4i ) : bool; overload; inline;

// quat
function _quat( const value : float ) : quat; overload; inline;
function _quat( const val3 : vec3; const w : float ) : quat; overload; inline;
function _quat( const fx, fy, fz, fw : float ) : quat; overload; inline;
function normalize( const v : quat ) : quat; overload; inline;
procedure rotate( var q : quat; const dir : vec3; const angle : float ); overload; inline;

// mat4
function _mat4( const value : float ) : mat4; overload; inline;
function _mat4( const colum : byte; const value : float ) : mat4; overload; inline;
function _mat4( const v1, v2, v3, v4 : vec4 ) : mat4; overload; inline;
function _mat4( const f00, f01, f02, f03, f10, f11, f12, f13, f20, f21, f22, f23, f30, f31, f32, f33 : float ) : mat4; overload; inline;
procedure rotate( var m : mat4; const rot : quat ); overload; inline;
function get( const m : mat4 ) : quat; overload; // inline;
procedure identity( var m : mat4 ); overload; inline;
procedure modelMatrix( var m : mat4; const pos : vec3; const rot : quat ); overload; inline;
procedure frustumMatrix( var m : mat4; const fovy, aspect, zNear, zFar : float ); overload; inline;
procedure orthoMatrix( var m : mat4; const l, r, b, t, zNear, zFar : float ); overload; inline;
// aabbox
function _aabbox( const min, max : vec3 ) : aabbox; overload; inline;
// other
// calcTangentSpace in/out params
procedure calcTangentSpace( var inVArr, inUVArr, inFArr, inTanArr; const inVCnt, inFCnt : ushort );
// textToVec3
function textToVec3( var inVec3Arr : pvec3arr; const inText : ansiString ) : enum;
// textToFaces
function textToFaces( var inFaceArr : pfaceArr; const inText : ansiString ) : enum;

const
  eps = 1.e-05;
  deg2rad = pi / 180;
  rad2deg = 180 / pi;
  // size vec
  sizeOfFace = sizeof( face );
  sizeOfVec2 = sizeof( vec2 );
  sizeOfVec2i = sizeof( vec2i );
  sizeOfVec3 = sizeof( vec3 );
  sizeOfVec3i = sizeof( vec3i );
  sizeOfVec4 = sizeof( vec4 );
  sizeOfVec4i = sizeof( vec4i );
  sizeOfMat4 = sizeof( mat4 );
  nullvec3 : vec3 = ( x : nullFloat; y : nullFloat; z : nullFloat );
  onevec3 : vec3 = ( x : oneFloat; y : oneFloat; z : oneFloat );
  identmat4 : mat4 = ( col00 : 1.0; col11 : 1.0; col22 : 1.0; col33 : 1.0 );

implementation

uses
  utils;

function max( const x, y : float ) : float;
begin
  if x > y then
    result := x
  else
    result := y;
end;

function min( const x, y : float ) : float;
begin
  if x < y then
    result := x
  else
    result := y;
end;

function max( const x, y : int ) : int;
begin
  if x > y then
    result := x
  else
    result := y;
end;

function min( const x, y : int ) : int;
begin
  if x < y then
    result := x
  else
    result := y;
end;

function clamp( const value, minf, maxf : float ) : float;
begin
  result := value;
  if result < minf then
    result := minf;
  if result > maxf then
    result := maxf;
end;

function clamp( const value, minf, maxf : int ) : int; overload; inline;
begin
  result := value;
  if result < minf then
    result := minf;
  if result > maxf then
    result := maxf;
end;

function clamp( const value, minf, maxf : time ) : time; overload; inline;
begin
  result := value;
  if result < minf then
    result := minf;
  if result > maxf then
    result := maxf;
end;
{$region 'math::operator(s)'}
// Trigonometry

{ std::vec3 }

// std::vec3::construct
class operator vec3.explicit( const value : float ) : vec3;
begin
  result := ( _vec3( value ) );
end;

// std::vec3::add
class operator vec3.add( const v1, v2 : vec3 ) : vec3;
begin
  result := ( add( v1, v2 ) );
end;

// std::vec3::sub
class operator vec3.subtract( const v1, v2 : vec3 ) : vec3;
begin
  result := ( sub( v1, v2 ) );
end;

// std::vec3::sub
class operator vec3.divide( const v1, v2 : vec3 ) : vec3;
begin
  result := ( divide( v1, v2 ) );
end;

// std::vec3::mul
class operator vec3.multiply( const v1, v2 : vec3 ) : vec3;
begin
  result := ( mul( v1, v2 ) );
end;

// std::vec3::mul
class operator vec3.multiply( const v : vec3; const f : float ) : vec3;
begin
  result := ( mul( v, f ) );
end;

// std::vec3::cmp
class operator vec3.equal( const v1, v2 : vec3 ) : bool;
begin
  result := ( cmp( v1, v1 ) );
end;

{ std::vec3i }

// std::vec3i::construct
class operator vec3i.explicit( const value : int ) : vec3i;
begin
  result := ( _vec3i( value ) );
end;

// std::vec3i::add
class operator vec3i.add( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( add( v1, v2 ) );
end;

// std::vec3i::sub
class operator vec3i.subtract( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( sub( v1, v2 ) );
end;

// std::vec3i::sub
class operator vec3i.divide( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( divide( v1, v2 ) );
end;

// std::vec3i::mul
class operator vec3i.multiply( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( mul( v1, v2 ) );
end;

// std::vec3i::mul
class operator vec3i.multiply( const v : vec3i; const f : int ) : vec3i;
begin
  result := ( mul( v, f ) );
end;

// std::vec3i::cmp
class operator vec3i.equal( const v1, v2 : vec3i ) : bool;
begin
  result := ( cmp( v1, v1 ) );
end;

{ std::vec4 }

// std::vec4::construct
class operator vec4.explicit( const value : float ) : vec4;
begin
  result := ( _vec4( value ) );
end;

// std::vec4::add
class operator vec4.add( const v1, v2 : vec4 ) : vec4;
begin
end;

// std::vec4::sub
class operator vec4.subtract( const v1, v2 : vec4 ) : vec4;
begin
end;

// std::vec4::sub
class operator vec4.divide( const v1, v2 : vec4 ) : vec4;
begin

end;

// std::vec4::mul
class operator vec4.multiply( const v1, v2 : vec4 ) : vec4;
begin

end;

// std::vec4::mul
class operator vec4.multiply( const v : vec4; const f : float ) : vec4;
begin

end;

// std::vec4::cmp
class operator vec4.equal( const v1, v2 : vec4 ) : bool;
begin
  result := ( cmp( v1, v1 ) );
end;

{ std::vec4i }

// std::vec4i::construct
class operator vec4i.explicit( const value : int ) : vec4i;
begin
  result := ( _vec4i( value ) );
end;

// std::vec4i::add
class operator vec4i.add( const v1, v2 : vec4i ) : vec4i;
begin

end;

// std::vec4i::sub
class operator vec4i.subtract( const v1, v2 : vec4i ) : vec4i;
begin

end;

// std::vec4i::sub
class operator vec4i.divide( const v1, v2 : vec4i ) : vec4i;
begin

end;

// std::vec4i::mul
class operator vec4i.multiply( const v1, v2 : vec4i ) : vec4i;
begin

end;

// std::vec4i::mul
class operator vec4i.multiply( const v : vec4i; const f : int ) : vec4i;
begin

end;

// std::vec4i::cmp
class operator vec4i.equal( const v1, v2 : vec4i ) : bool;
begin
  result := ( cmp( v1, v1 ) );
end;

{ std::mat4 }

// std::mat4::mul
class operator mat4.multiply( const m1, m2 : mat4 ) : mat4;
begin
end;

// std::mat4::mul
class operator mat4.multiply( const m1 : mat4; const v2 : vec4 ) : vec4;
begin
end;
{$endregion}
{$region 'math::function(s)'}

// vec2
// std::_vec2::constructor
function _vec2( const x, y : float ) : vec2;
begin
  result.x := x;
  result.y := y;
end;

// std::_vec2::constructor
function _vec2( const value : float ) : vec2;
begin
  result := ( _vec2( value, value ) );
end;

// vec3

// std::vec3::constructor
function _vec3( const value : float ) : vec3;
begin
  result := ( _vec3( value, value, value ) );
end;

// std::vec3::constructor
function _vec3( const xy : vec2; const z : float ) : vec3;
begin
  result := ( _vec3( xy.x, xy.y, z ) );
end;

// std::vec3::constructor
function _vec3( const fx, fy, fz : float ) : vec3;
begin
  result.x := fx;
  result.y := fy;
  result.z := fz;
end;

// std::vec3::add
function add( const v1, v2 : vec3 ) : vec3;
begin
  result := ( _vec3( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ) );
end;

// std::vec3::sub
function sub( const v1, v2 : vec3 ) : vec3;
begin
  result := ( _vec3( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ) );
end;

// std::vec3::divide
function divide( const v1, v2 : vec3 ) : vec3;
begin
  result := ( _vec3( v1.x / v2.x, v1.y / v2.y, v1.z / v2.z ) );
end;

// std::vec3::mul
function mul( const v1, v2 : vec3 ) : vec3;
begin
  result := ( _vec3( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ) );
end;

// std::vec3::mul
function mul( const v : vec3; const f : float ) : vec3;
begin
  result := ( _vec3( v.x * f, v.y * f, v.z * f ) );
end;

// std::vec3::cross
function cross( const v1, v2 : vec3 ) : vec3;
begin
  result := ( _vec3( v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x ) );
end;

// std::vec3::dot
function dot( const v1, v2 : vec3 ) : float;
begin
  result := ( v1.x * v2.x + v1.y * v2.y + v1.z * v2.z );
end;

// std::vec3::normalize
function normalize( const v : vec3 ) : vec3;
begin
  result.x := length( v );
  if result.x > eps then
    result := ( v * ( 1.0 / result.x ) )
  else
    result := ( _vec3( 0.0 ) );
end;

// std::vec3::lengthsqr
function lengthsqr( const v : vec3 ) : float;
begin
  result := ( sqr( v.x ) + sqr( v.y ) + sqr( v.z ) );
end;

// std::vec3::length
function length( const v : vec3 ) : float;
begin
  result := ( sqrt( lengthsqr( v ) ) );
end;

// std::vec3::cmp
function cmp( const v1, v2 : vec3 ) : bool;
begin
  result := ( ( abs( v1.x - v2.x ) <= eps ) and ( abs( v1.y - v2.y ) <= eps ) and ( abs( v1.z - v2.z ) <= eps ) );
end;
// std::vec3::cross

// vec3i

// std::vec3i::constructor
function _vec3i( const value : int ) : vec3i;
begin
 // todo: check asm code!!
  fillchar( result, sizeOfVec3i, value );
end;

// std::vec3i::constructor
function _vec3i( const xy : vec2i; const z : int ) : vec3i;
begin
  result := ( _vec3i( xy.x, xy.y, z ) );
end;

// std::vec3i::constructor
function _vec3i( const fx, fy, fz : int ) : vec3i;
begin
  result.x := fx;
  result.y := fy;
  result.z := fz;
end;

// std::vec3i::add
function add( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( _vec3i( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ) );
end;

// std::vec3i::sub
function sub( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( _vec3i( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ) );
end;

// std::vec3i::divide
function divide( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( _vec3i( v1.x div v2.x, v1.y div v2.y, v1.z div v2.z ) );
end;

// std::vec3i::mul
function mul( const v1, v2 : vec3i ) : vec3i;
begin
  result := ( _vec3i( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ) );
end;

// std::vec3i::mul
function mul( const v : vec3i; const f : int ) : vec3i;
begin
  result := ( _vec3i( v.x * f, v.y * f, v.z * f ) );
end;

// std::vec3i::cross
function cross( const v1, v2 : vec3i ) : vec3i;
begin

end;

// std::vec3i::cross
function dot( const v1, v2 : vec3i ) : int;
begin
  result := ( v1.x * v2.x + v1.y * v2.y + v1.z * v2.z );
end;

// std::vec3i::cmp
function cmp( const v1, v2 : vec3i ) : bool;
begin
  result := ( ( v1.x = v2.x ) and ( v1.y = v2.y ) and ( v1.z = v2.z ) );
end;

//
// vec4
//

// std::vec4::constructor
function _vec4( const value : float ) : vec4;
begin
  result := ( _vec4( value, value, value, value ) );
end;

// std::vec4::constructor
function _vec4( const val3 : vec3; const w : float ) : vec4;
begin
  result := ( _vec4( val3.x, val3.y, val3.z, w ) );
end;

// std::vec4::constructor
function _vec4( const fx, fy, fz, fw : float ) : vec4;
begin
  result.x := fx;
  result.y := fy;
  result.z := fz;
  result.w := fw;
end;

function cmp( const v1, v2 : vec4 ) : bool;
begin
  result := ( ( abs( v1.x - v2.x ) <= eps ) and ( abs( v1.y - v2.y ) <= eps ) and ( abs( v1.z - v2.z ) <= eps ) and ( abs( v1.w - v2.w ) <= eps ) );
end;

{ std::vec4i }

// std::vec4i::constructor
function _vec4i( const value : int ) : vec4i;
begin
  fillchar( result, sizeOfVec4i, value );
end;

// std::vec4i::constructor
function _vec4i( const val3i : vec3i; const w : int ) : vec4i;
begin
  result := ( _vec4i( val3i.x, val3i.y, val3i.z, w ) );
end;

// std::vec4i::constructor
function _vec4i( const fx, fy, fz, fw : int ) : vec4i;
begin
  result.x := fx;
  result.y := fy;
  result.z := fz;
  result.w := fw;
end;

// std::vec4::cmp
function cmp( const v1, v2 : vec4i ) : bool;
begin
  result := ( ( v1.x = v2.x ) and ( v1.y = v2.y ) and ( v1.z = v2.z ) );
end;

// quat
// std::quat::constructor
function _quat( const value : float ) : quat;
begin
  result := _vec4( value );
end;

// std::quat::constructor
function _quat( const val3 : vec3; const w : float ) : quat;
begin
  result := _vec4( val3, w );
end;

// std::quat::constructor
function _quat( const fx, fy, fz, fw : float ) : quat;
begin
  result := _vec4( fx, fy, fz, fw );
end;

// std::quat::normalize
function normalize( const v : quat ) : quat;
begin
  result.w := sqrt( sqr( v.x ) + sqr( v.y ) + sqr( v.z ) + sqr( v.w ) );
  if result.w > 0 then
  begin
    result.w := 1.0 / result.w;
    result.x := v.x * result.w;
    result.y := v.y * result.w;
    result.z := v.z * result.w;
    result.w := v.w * result.w;
  end
  else
    result := _quat( 0.0 );
end;

// std::quat::normalize
procedure rotate( var q : quat; const dir : vec3; const angle : float );
var
  s, c : float;
begin
  c := angle * 0.5; // half
  s := sin( c );
  c := cos( c );
  q.x := dir.x * s;
  q.y := dir.y * s;
  q.z := dir.z * s;
  q.w := c;
  q := normalize( q );
end;

// mat4
// std::mat4::constructor
function _mat4( const value : float ) : mat4;
begin
  result := ( _mat4( _vec4( value ), _vec4( value ), _vec4( value ), _vec4( value ) ) );
end;

// std::mat4::constructor
function _mat4( const colum : byte; const value : float ) : mat4;
begin
  fillchar( result, sizeOfMat4, nullInt );
  result.col[ colum ] := _vec4( value );
end;

// std::mat4::constructor
function _mat4( const v1, v2, v3, v4 : vec4 ) : mat4;
begin
  result.first := v1;
  result.second := v2;
  result.third := v3;
  result.pos := v4;
end;

// std::mat4::constructor
function _mat4( const f00, f01, f02, f03, f10, f11, f12, f13, f20, f21, f22, f23, f30, f31, f32, f33 : float ) : mat4;
begin
  result.col00 := f00;
  result.col01 := f01;
  result.col02 := f02;
  result.col03 := f03;

  result.col10 := f10;
  result.col11 := f11;
  result.col12 := f12;
  result.col13 := f13;

  result.col20 := f20;
  result.col21 := f21;
  result.col22 := f22;
  result.col23 := f23;

  result.col30 := f30;
  result.col31 := f31;
  result.col32 := f32;
  result.col33 := f33;
end;

// std::mat4::rotate
procedure rotate( var m : mat4; const rot : quat );
var
  sqw, sqx, sqy, sqz, invs : float;
  tmp1, tmp2 : float;
begin
  with rot do
  begin
    sqw := w * w;
    sqx := x * x;
    sqy := y * y;
    sqz := z * z;

    invs := 1 / ( sqx + sqy + sqz + sqw );
    m.col00 := ( sqx - sqy - sqz + sqw ) * invs;
    m.col11 := ( -sqx + sqy - sqz + sqw ) * invs;
    m.col22 := ( -sqx - sqy + sqz + sqw ) * invs;

    tmp1 := x * y;
    tmp2 := z * w;
    m.col10 := 2 * ( tmp1 + tmp2 ) * invs;
    m.col01 := 2 * ( tmp1 - tmp2 ) * invs;

    tmp1 := x * z;
    tmp2 := y * w;
    m.col20 := 2 * ( tmp1 - tmp2 ) * invs;
    m.col02 := 2 * ( tmp1 + tmp2 ) * invs;

    tmp1 := y * z;
    tmp2 := x * w;
    m.col21 := 2 * ( tmp1 + tmp2 ) * invs;
    m.col12 := 2 * ( tmp1 - tmp2 ) * invs;
  end;
end;

// std::mat4::get
function get( const m : mat4 ) : quat;
var
  t, s : float;
begin
  t := m.col00 + m.col11 + m.col22 + 1;
  with result, m do
    if t > eps then
    begin
     s := 0.5 / sqrt( t );
     w := 0.25 / s;
     x := ( col21 - col12 ) * s;
     y := ( col02 - col20 ) * s;
     z := ( col10 - col01 ) * s;
    end
    else
    begin
     if ( col00 > col11 ) and ( col00 > col22 ) then
     begin
     s := 2 * sqrt( 1 + col00 - col11 - col22 );
     w := ( col21 - col12 ) / s;
     x := 0.25 * s;
     y := ( col01 + col10 ) / s;
     z := ( col02 + col20 ) / s;
     end
     else
     if col11 > col22 then
     begin
     s := 2 * sqrt( 1 + col11 - col00 - col22 );
     w := ( col02 - col20 ) / s;
     x := ( col01 + col10 ) / s;
     y := 0.25 * s;
     z := ( col12 + col21 ) / s;
     end
     else
     begin
     s := 2 * sqrt( 1 + col22 - col00 - col11 );
     w := ( col10 - col01 ) / s;
     x := ( col02 + col20 ) / s;
     y := ( col12 + col21 ) / s;
     z := 0.25 * s;
     end;
    end;
// normalize result
  result := normalize( result );
end;

// std::mat4::identity
procedure identity( var m : mat4 );
begin
  m := identmat4;
end;

// std::mat4::modelMatrix
procedure modelMatrix( var m : mat4; const pos : vec3; const rot : quat );
begin
  identity( m );
  rotate( m, rot );
  m.pos.xyz := pos;
end;

// std::mat4::frustumMatrix
procedure frustumMatrix( var m : mat4; const fovy, aspect, zNear, zFar : float );
var
  radians, deltaZ, sine, cotangent : float;
begin
  radians := fovy / 2 * pi / 180;
  deltaZ := zFar - zNear;
  sine := sin( radians );
 // todo : optimize
  cotangent := cos( radians ) / sine;
  identity( m );
  m.rows[ 0, 0 ] := cotangent / aspect;
  m.rows[ 1, 1 ] := cotangent;
  m.rows[ 2, 2 ] := -( zFar + zNear ) / deltaZ;
  m.rows[ 2, 3 ] := -1;
  m.rows[ 3, 2 ] := -2 * zNear * zFar / deltaZ;
  m.rows[ 3, 3 ] := 0;
end;

// std::mat4::orthoMatrix
procedure orthoMatrix( var m : mat4; const l, r, b, t, zNear, zFar : float );
begin
  m.rows[ 0, 0 ] := 2 / ( r - l );
  m.rows[ 1, 0 ] := 0;
  m.rows[ 2, 0 ] := 0;
  m.rows[ 3, 0 ] := 0;
  m.rows[ 0, 1 ] := 0;
  m.rows[ 1, 1 ] := 2 / ( t - b );
  m.rows[ 2, 1 ] := 0;
  m.rows[ 3, 1 ] := 0;

  m.rows[ 0, 2 ] := 0;
  m.rows[ 1, 2 ] := 0;
  m.rows[ 2, 2 ] := -2 / ( zFar - zNear );
  m.rows[ 3, 2 ] := 0;

  m.rows[ 0, 3 ] := ( r + l ) / ( r - l );
  m.rows[ 1, 3 ] := ( t + b ) / ( t - b );
  m.rows[ 2, 3 ] := ( zFar + zNear ) / ( zFar - zNear );
  m.rows[ 3, 3 ] := 1;
end;

// aabbox
// std::_aabbox::constructor
function _aabbox( const min, max : vec3 ) : aabbox;
begin

end;
{$endregion}

// other
// note: no use real time!
procedure calcTangentSpace( var inVArr, inUVArr, inFArr, inTanArr; const inVCnt, inFCnt : ushort );
var
  i : int;
  vertex : array of vec3 absolute inVArr;
  texcoord : array of vec3 absolute inUVArr;
  faces : array of face absolute inFArr;
  tangents : array of vec3 absolute inTanArr;
  v1, v2, v3 : vec3;
  uv1, uv2, uv3 : vec3;
  tan, bin, nm : vec3;
  f : float;
  hand : bool;
begin
  for i := 0 to ( inFCnt - 1 ) div 3 do
  begin
    v1 := vertex[ faces[ i ].one ];
    v2 := vertex[ faces[ i ].two ] - v1;
    v3 := vertex[ faces[ i ].three ] - v1;

    uv1 := texcoord[ faces[ i ].one ];
    uv2 := texcoord[ faces[ i ].two ] - uv1;
    uv3 := texcoord[ faces[ i ].three ] - uv1;

    f := uv2.x * uv3.y - uv2.y * uv3.x;

    if abs( f ) <= eps then
     f := 1.0
    else
     f := 1.0 / f;

    tan := normalize( ( v2 * uv3.y ) - ( v3 * uv2.y ) * f );

    bin := normalize( ( v3 * uv2.x ) - ( v2 * uv3.x ) * f );

    nm := normalize( cross( tan, bin ) );

    tan := tan - ( nm * dot( nm, tan ) );

    hand := abs( dot( cross( tan, bin ), nm ) ) >= eps;

    bin := cross( nm, tan );

    if hand then
     bin := bin * -1;

    tangents[ faces[ i ].one ] := tan;
    tangents[ faces[ i ].two ] := tan;
    tangents[ faces[ i ].three ] := tan;
  end;
end;

// textToVec3
function textToVec3( var inVec3Arr : pvec3arr; const inText : ansiString ) : handle;
var
  curr, last : uint;
  tmp : pvec3arr;
begin
  curr := nullInt;
  last := oneInt;
  getmem( inVec3Arr, sizeOfVec3 * ( strCntLine( inText ) + 1 ) );
  tmp := inVec3Arr;
  result := strLn( inText );
  while curr <= result do
  begin
    inc( curr );
  // todo: cross platform conflict!
    if ( result = curr - 1 ) or ( inText[ curr ] = #32 ) or ( inText[ curr ] = #13 ) then
    begin
     pfloat( tmp )^ := strFloat( strTrim( Copy( inText, last, ( curr - last ) ) ), nullFloat );
     int( tmp ) := int( tmp ) + 4;
     last := curr + 1;
    end;
  end;

  result := strCntLine( inText );
end;

// textToFaces
function textToFaces( var inFaceArr : pfaceArr; const inText : ansiString ) : handle;
var
  curr, last : uint;
  tmp : pfaceArr;
begin
  curr := nullInt;
  last := oneInt;
  getmem( inFaceArr, sizeOfFace * ( strCntLine( inText ) + 1 ) );
  tmp := inFaceArr;
  result := strLn( inText );
  while curr <= result do
  begin
    inc( curr );
  // todo: cross platform conflict!
    if ( result = curr - 1 ) or ( inText[ curr ] = #32 ) or ( inText[ curr ] = #13 ) then
    begin
     pushort( tmp )^ := strInt( strTrim( Copy( inText, last, ( curr - last ) ) ), nullInt );
     int( tmp ) := int( tmp ) + 2;
     last := curr + 1;
    end;
  end;

  result := strCntLine( inText );
end;

end.
